/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.model.statistics;

import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.ArrayList;
import java.text.SimpleDateFormat;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Temporal;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQuery;
import javax.persistence.PrePersist;
import javax.persistence.TemporalType;
import org.hibernate.validator.Min;
import org.hibernate.validator.NotNull;
import org.internna.iwebmvc.utils.Assert;
import org.internna.iwebjtracker.model.DefaultProject;
import org.internna.iwebmvc.model.AbstractDomainEntity;

import static org.internna.iwebmvc.utils.StringUtils.EMPTY;

/**
 * Groups the number of open and closed issues per day for reporting uses.
 *
 * @author Jose Noheda
 * @since 1.0
 */
@Entity
@Table(name = "OPENCLOSED_STATISTICS")
@NamedQuery(name = "OpenClosed.findAll", query = "SELECT o FROM OpenClosed o")
public class OpenClosed extends AbstractDomainEntity {

    private static SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd", Locale.ENGLISH);

    @NotNull
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "PROJECT", updatable = false)
    private DefaultProject project;

    @NotNull
    @Temporal(TemporalType.DATE)
    @Column(name = "GENERATION", updatable = false)
    private Date date;

    @Min(0)
    @Column(name = "OPENED", updatable = false)
    private int open = 0;

    @Min(0)
    @Column(name = "CLOSED", updatable = false)
    private int closed = 0;

    /**
     * Accessor method.
     *
     * @return a positive number
     */
    public int getOpen() {
        return open;
    }

    /**
     * Accessor method.
     *
     * @param open any (only possitive numbers are stored)
     */
    protected void setOpen(int open) {
        if (open >= 0) {
            this.open = open;
        }
    }

    /**
     * Adds a quantity to the open issues count.
     *
     * @param open a positive integer
     */
    public void addOpen(int open) {
        if (open > 0) {
            this.open += open;
        }
    }

    /**
     * Accessor method.
     *
     * @return a positive number
     */
    public int getClosed() {
        return closed;
    }

    /**
     * Accessor method.
     *
     * @param closed any (only possitive numbers are stored)
     */
    public void setClosed(int closed) {
        if (closed >= 0) {
            this.closed = closed;
        }
    }

    /**
     * Accessor method.
     *
     * @return a non null date
     */
    public Date getDate() {
        return date == null ? null : new Date(date.getTime());
    }

    /**
     * Accessor method.
     *
     * @param date any  non null instance
     */
    protected void setDate(Date date) {
        Assert.notNull(date);
        this.date = date;
    }

    /**
     * Accessor method.
     *
     * @return a non null instance
     */
    public DefaultProject getProject() {
        return project;
    }

    /**
     * Accessor method.
     *
     * @param project a non null instance
     */
    public void setProject(DefaultProject project) {
        Assert.notNull(project);
        this.project = project;
    }

    /**
     * Invoked automatically
     */
    @PrePersist
    protected void before() {
        setDate(new Date());
    }

    /**
     * This entity is not meant to be displayed in the UI as is.
     *
     * @param locale any
     * @return null
     */
    @Override public String getCaption(Locale locale) {
        return null;
    }

    /**
     * Merges two elements if they share the same date. If the project is also shared
     * it will be preserved, otherwise it'll be removed. If the date is not shared both
     * elements are returned.
     *
     * @param other any
     * @return a non empty collection
     */
    public List<OpenClosed> merge(OpenClosed other) {
        List<OpenClosed> merged = new ArrayList<OpenClosed>();
        if (other != null) {
            String thisDate = date == null ? null : formatter.format(date);
            String otherDate = other.date == null ? EMPTY : formatter.format(other.date);
            if (otherDate.equals(thisDate)) {
                OpenClosed openClosed = doMerge(other);
                merged.add(openClosed);
                return merged;
            }
            merged.add(other);
        }
        merged.add(this);
        return merged;
    }

    private OpenClosed doMerge(OpenClosed other) {
        OpenClosed openClosed = new OpenClosed();
        openClosed.setDate(date);
        openClosed.addOpen(open);
        openClosed.addOpen(other.open);
        openClosed.setClosed(closed + other.closed);
        if ((project != null) && (project.equals(other.project))) {
            openClosed.setProject(project);
        }
        return openClosed;
    }

}
